package com.lzqinga.service.storage;

import com.lzqinga.model.VideoSegment;
import com.lzqinga.service.VideoGeneratorService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

@Slf4j
@Service
public class VideoCompositionService {
    @Autowired
    private LocalStorageService storageService;

    @Value("${ffmpeg.path}")
    private String ffmpegPath;

    @Value("${app.video.transitions.enabled}")
    private Boolean enableTransitions;

    @Value("${app.video.transitions.duration}")
    private Double defaultTransitionDuration;

    @Value("${app.video.threads:10}") // 默认使用10个线程
    private int ffmpegThreads;

    @Value("${app.video.gpu.enabled:true}")
    private boolean gpuAccelerationEnabled;

    @Value("${app.video.gpu.device:}")
    private String gpuDevice;

    // 操作系统检测
    private static final boolean IS_WINDOWS = SystemUtils.IS_OS_WINDOWS;
    private static final boolean IS_LINUX = SystemUtils.IS_OS_LINUX;
    private static final boolean IS_MAC = SystemUtils.IS_OS_MAC;

    /**
     * 合成多个视频片段（支持转场效果）
     */
    public String composeVideoSegments(List<String> segmentPaths,
                                       List<VideoGeneratorService.Segment> segments,
                                       String outputFileName) {
        if (segmentPaths.isEmpty()) {
            throw new IllegalArgumentException("视频片段列表不能为空");
        }

        String outputPath = outputFileName + UUID.randomUUID() + ".mp4";

        try {
            log.info("开始合成视频，共{}个片段", segmentPaths.size());

            if (segmentPaths.size() == 1) {
                // 单片段，直接复制
                Files.copy(Paths.get(segmentPaths.get(0)), Paths.get(outputPath));
                log.info("单片段视频合成完成: {}", outputPath);
                return outputPath;
            }

            if (enableTransitions && segments != null && gpuAccelerationEnabled) {
                // 使用转场效果合成（硬件加速）
                return composeWithHardwareAcceleration(segmentPaths, segments, outputPath);
            } else if (enableTransitions && segments != null) {
                // 使用转场效果合成（软件）
                return composeWithTransitions(segmentPaths, segments, outputPath);
            } else {
                // 简单拼接合成
                return composeSimple(segmentPaths, outputPath);
            }

        } catch (Exception e) {
            log.error("视频合成失败", e);
            throw new RuntimeException("视频合成失败: " + e.getMessage());
        }
    }

    /**
     * 使用硬件加速合成视频（带转场效果）
     */
    private String composeWithHardwareAcceleration(List<String> segmentPaths,
                                                   List<VideoGeneratorService.Segment> segments,
                                                   String outputPath) {
        try {
            // 构建硬件加速命令
            List<String> cmd = new ArrayList<>();
            cmd.add(ffmpegPath);
            cmd.add("-y");

            // 添加硬件加速参数
            addHardwareAccelerationParams(cmd);

            // 添加所有输入文件
            for (String file : segmentPaths) {
                cmd.add("-i");
                cmd.add(file);
            }

            // 构建硬件加速滤镜链
            String filterComplex = buildHardwareTransitionFilter(segmentPaths, segments);
            cmd.add("-filter_complex");
            cmd.add(filterComplex);

            // 输出参数
            cmd.add("-map");
            cmd.add("[v]");
            cmd.add("-map");
            cmd.add("[a]");

            // 硬件编码参数 - 使用更稳定的设置
            if (IS_WINDOWS) {
                // 针对Intel Arc显卡优化QSV设置
                cmd.add("-c:v");
                cmd.add("h264_qsv");
                cmd.add("-preset");
                cmd.add("veryfast");
                cmd.add("-look_ahead");
                cmd.add("0"); // 禁用前瞻
                cmd.add("-g");
                cmd.add("60"); // GOP大小
                cmd.add("-b:v");
                cmd.add("5M"); // 比特率控制
            } else {
                cmd.add("-c:v");
                cmd.add("hevc_vaapi");
                cmd.add("-global_quality");
                cmd.add("25");
            }

            cmd.add("-c:a");
            cmd.add("aac");
            cmd.add("-b:a");
            cmd.add("192k");

            // 多线程优化
            cmd.add("-threads");
            cmd.add(String.valueOf(ffmpegThreads));
            cmd.add("-filter_threads");
            cmd.add(String.valueOf(Math.max(1, ffmpegThreads / 2)));

            // 添加调试日志
            cmd.add("-loglevel");
            cmd.add("debug");

            cmd.add(outputPath);

            executeCommand(cmd);

            log.info("带转场效果视频合成完成: {}", outputPath);
            return outputPath;

        } catch (Exception e) {
            log.error("带转场效果合成失败，尝试软件转场合成", e);
            // 降级到软件转场合成
            return composeWithTransitions(segmentPaths, segments, outputPath);
        }
    }

    /**
     * 添加硬件加速参数（跨平台）
     */
    private void addHardwareAccelerationParams(List<String> cmd) {
        if (IS_WINDOWS) {
            // Windows 使用 D3D11VA 加速
            cmd.add("-hwaccel");
            cmd.add("d3d11va");
            cmd.add("-hwaccel_output_format");
            cmd.add("d3d11");

            // 针对Intel Arc显卡的额外参数
            cmd.add("-hwaccel_device");
            cmd.add("0"); // 使用默认设备
        } else if (IS_LINUX) {
            // Linux 使用 VAAPI
            cmd.add("-hwaccel");
            cmd.add("vaapi");

            // 指定GPU设备（如果配置了）
            if (!gpuDevice.isEmpty()) {
                cmd.add("-hwaccel_device");
                cmd.add(gpuDevice);
            } else {
                // 尝试自动检测设备
                cmd.add("-hwaccel_device");
                cmd.add("/dev/dri/renderD128");
            }

            cmd.add("-hwaccel_output_format");
            cmd.add("vaapi");
        } else if (IS_MAC) {
            // macOS 使用 VideoToolbox
            cmd.add("-hwaccel");
            cmd.add("videotoolbox");
            cmd.add("-hwaccel_output_format");
            cmd.add("nv12");
        }
    }


    /**
     * 构建硬件加速转场滤镜（跨平台）
     */
    private String buildHardwareTransitionFilter(List<String> segmentPaths,
                                                 List<VideoGeneratorService.Segment> segments) {
        StringBuilder filter = new StringBuilder();
        int segmentCount = segmentPaths.size();

        // 1. 为每个输入创建流标签并上传到GPU
        for (int i = 0; i < segmentCount; i++) {
            if (IS_WINDOWS) {
                // Windows 使用更简单的格式转换
                filter.append(String.format(
                        "[%d:v]format=nv12,setpts=PTS-STARTPTS[v%d];",
                        i, i
                ));
            } else if (IS_LINUX) {
                // Linux 使用 VAAPI
                filter.append(String.format(
                        "[%d:v]format=nv12|vaapi,hwupload,setpts=PTS-STARTPTS[v%d];",
                        i, i
                ));
            } else {
                filter.append(String.format(
                        "[%d:v]setpts=PTS-STARTPTS[v%d];",
                        i, i
                ));
            }

            filter.append(String.format(
                    "[%d:a]asetpts=PTS-STARTPTS[a%d];",
                    i, i
            ));
        }

        // 2. 应用转场效果（硬件加速）
        for (int i = 0; i < segmentCount - 1; i++) {
            VideoGeneratorService.Segment currentSegment = segments.get(i);
            String transitionType = currentSegment.transition != null ?
                    currentSegment.transition : "fade";
            double transitionDuration = currentSegment.transition != null ?
                    currentSegment.transitionDuration : defaultTransitionDuration;

            // 简化转场效果，避免复杂操作
            filter.append(buildSimpleTransition(i, i + 1, transitionType, transitionDuration));
        }

        // 3. 最终连接
        filter.append("[v0]");
        for (int i = 1; i < segmentCount; i++) {
            filter.append("[v").append(i).append("t]");
        }

        if (IS_LINUX) {
            filter.append("concat=n=").append(segmentCount).append(":v=1:a=0,format=nv12|vaapi[v];");
        } else {
            filter.append("concat=n=").append(segmentCount).append(":v=1:a=0[v];");
        }

        // 4. 音频连接 - 简化处理
        filter.append("[a0]");
        for (int i = 1; i < segmentCount; i++) {
            filter.append("[a").append(i).append("]");
        }
        filter.append("concat=n=").append(segmentCount).append(":v=0:a=1[a]");

        return filter.toString();
    }

    /**
     * 构建简化的转场滤镜（解决兼容性问题）
     */
    private String buildSimpleTransition(int fromIndex, int toIndex, String transitionType, double duration) {
        // 默认使用淡入淡出效果，避免复杂转场
        String safeTransition = "fade";

        // 计算偏移时间
        double offset = duration * fromIndex;

        if (IS_LINUX) {
            // Linux 使用 xfade_vaapi
            return String.format(
                    "[v%d][v%d]xfade_vaapi=transition=%s:duration=%.2f:offset=%.2f[v%dt];",
                    fromIndex, toIndex, safeTransition, duration, offset, toIndex
            );
        } else {
            // Windows 和其他平台使用标准 xfade
            return String.format(
                    "[v%d][v%d]xfade=transition=%s:duration=%.2f:offset=%.2f[v%dt];",
                    fromIndex, toIndex, safeTransition, duration, offset, toIndex
            );
        }
    }

    /**
     * 执行命令（优化版）
     */
    private void executeCommand(List<String> command) {
        try {
            log.debug("执行命令: {}", String.join(" ", command));

            ProcessBuilder pb = new ProcessBuilder(command);
            pb.redirectErrorStream(true);
            Process process = pb.start();

            // 创建日志收集器
            StringBuilder outputLog = new StringBuilder();

            // 异步读取输出
            Thread readerThread = new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        outputLog.append(line).append("\n");

                        // 实时记录错误和警告
                        if (line.contains("error") || line.contains("Error") || line.contains("failed")) {
                            log.error("FFmpeg: {}", line);
                        } else if (line.contains("warning") || line.contains("Warning")) {
                            log.warn("FFmpeg: {}", line);
                        } else {
                            log.debug("FFmpeg: {}", line);
                        }
                    }
                } catch (Exception e) {
                    log.warn("读取命令输出失败", e);
                }
            });
            readerThread.start();

            int exitCode = process.waitFor();
            readerThread.join(); // 确保日志读取完成

            if (exitCode != 0) {
                // 将完整日志记录到文件以便调试
                String errorLogPath = saveErrorLog(outputLog.toString());
                log.error("命令执行失败 (exit code: {}), 完整日志已保存到: {}", exitCode, errorLogPath);

                throw new RuntimeException("命令执行失败 (exit code: " + exitCode + ")");
            }

        } catch (Exception e) {
            throw new RuntimeException("执行命令失败: " + e.getMessage(), e);
        }
    }

    /**
     * 保存错误日志到文件
     */
    private String saveErrorLog(String logContent) {
        try {
            String logPath = storageService.generateTempFilePath("ffmpeg_error", "log");
            Files.write(Paths.get(logPath), logContent.getBytes());
            return logPath;
        } catch (Exception e) {
            log.error("保存错误日志失败", e);
            return "无法保存日志文件";
        }
    }

    /**
     * 使用转场效果合成视频（软件）
     */
    private String composeWithTransitions(List<String> segmentPaths,
                                          List<VideoGeneratorService.Segment> segments,
                                          String outputPath) {
        try {
            // 简化滤镜链，避免复杂操作
            String filterComplex = buildSimpleTransitionFilter(segmentPaths, segments);

            List<String> cmd = new ArrayList<>();
            cmd.add(ffmpegPath);
            cmd.add("-y");

            // 添加所有输入文件
            for (String file : segmentPaths) {
                cmd.add("-i");
                cmd.add(file);
            }

            // 添加滤镜复杂度
            cmd.add("-filter_complex");
            cmd.add(filterComplex);

            // 输出参数 - 使用更稳定的编码器
            cmd.add("-map");
            cmd.add("[v]");
            cmd.add("-map");
            cmd.add("[a]");
            cmd.add("-c:v");
            cmd.add("libx264");
            cmd.add("-preset");
            cmd.add("fast");
            cmd.add("-c:a");
            cmd.add("aac");
            cmd.add("-pix_fmt");
            cmd.add("yuv420p");
            cmd.add("-movflags");
            cmd.add("+faststart");

            // 多线程优化
            cmd.add("-threads");
            cmd.add(String.valueOf(ffmpegThreads));

            cmd.add(outputPath);

            executeCommand(cmd);

            log.info("软件转场效果视频合成完成: {}", outputPath);
            return outputPath;

        } catch (Exception e) {
            log.error("软件转场效果合成失败，尝试简单合成", e);
            // 降级到简单合成
            return composeSimple(segmentPaths, outputPath);
        }
    }

    /**
     * 构建简化的转场滤镜（软件）
     */
    private String buildSimpleTransitionFilter(List<String> segmentPaths, List<VideoGeneratorService.Segment> segments) {
        StringBuilder filter = new StringBuilder();
        int segmentCount = segmentPaths.size();

        // 1. 为每个输入创建流标签
        for (int i = 0; i < segmentCount; i++) {
            filter.append("[").append(i).append(":v]").append("setpts=PTS-STARTPTS[v").append(i).append("];");
            filter.append("[").append(i).append(":a]").append("asetpts=PTS-STARTPTS[a").append(i).append("];");
        }

        // 2. 应用简化的转场效果
        for (int i = 0; i < segmentCount - 1; i++) {
            // 只使用淡入淡出效果
            double transitionDuration = defaultTransitionDuration;
            filter.append(buildSimpleXFadeTransition(i, i + 1, transitionDuration));
        }

        // 3. 最终连接
        filter.append("[v0]");
        for (int i = 1; i < segmentCount; i++) {
            filter.append("[v").append(i).append("t]");
        }
        filter.append("concat=n=").append(segmentCount).append(":v=1:a=0[v];");

        // 4. 音频连接
        filter.append("[a0]");
        for (int i = 1; i < segmentCount; i++) {
            filter.append("[a").append(i).append("]");
        }
        filter.append("concat=n=").append(segmentCount).append(":v=0:a=1[a]");

        return filter.toString();
    }

    /**
     * 构建简化的xfade转场滤镜
     */
    private String buildSimpleXFadeTransition(int fromIndex, int toIndex, double duration) {
        // 简化偏移计算
        double offset = duration * fromIndex;
        return String.format(
                "[v%d][v%d]xfade=transition=fade:duration=%.2f:offset=%.2f[v%dt];",
                fromIndex, toIndex, duration, offset, toIndex
        );
    }

    /**
     * 计算转场偏移时间
     */
    private String calculateTransitionOffset(int segmentIndex, double transitionDuration) {
        // 这里需要根据实际片段时长计算偏移
        // 简化实现：假设每个片段5秒，减去转场时长
        double baseDuration = 5.0; // 应该从实际片段获取
        return String.format("%.2f", segmentIndex * baseDuration - transitionDuration);
    }

    /**
     * 简单拼接合成
     */
    private String composeSimple(List<String> segmentPaths, String outputPath) {
        try {
            // 创建文件列表
            String listFilePath = storageService.generateTempFilePath("filelist", "txt");
            StringBuilder fileList = new StringBuilder();

            for (String file : segmentPaths) {
                fileList.append("file '").append(new File(file).getAbsolutePath()).append("'\n");
            }

            Files.write(Paths.get(listFilePath), fileList.toString().getBytes());

            // 构建命令
            List<String> cmd = new ArrayList<>();
            cmd.add(ffmpegPath);
            cmd.add("-y");
            cmd.add("-f");
            cmd.add("concat");
            cmd.add("-safe");
            cmd.add("0");
            cmd.add("-i");
            cmd.add(listFilePath.toString());
            cmd.add("-c");
            cmd.add("copy");
            cmd.add(outputPath);

            executeCommand(cmd);

            // 删除临时列表文件
            Files.deleteIfExists(Paths.get(listFilePath));

            log.info("简单拼接视频合成完成: {}", outputPath);
            return outputPath;

        } catch (Exception e) {
            throw new RuntimeException("简单拼接合成失败: " + e.getMessage(), e);
        }
    }
}